package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"sync"
)

// RedisProxyConfig Redis代理配置
type RedisProxyConfig struct {
	LocalAddr  string // 本地监听地址
	RemoteAddr string // 远程Redis地址
}

// RedisServer Redis代理服务器
type RedisServer struct {
	config    RedisProxyConfig
	listener  net.Listener
	isRunning bool
	mu        sync.Mutex
	wg        sync.WaitGroup
}

// NewRedisServer 创建新的Redis代理服务器
func NewRedisServer(config RedisProxyConfig) (*RedisServer, error) {
	return &RedisServer{
		config:    config,
		isRunning: false,
	}, nil
}

// Start 启动Redis代理
func (s *RedisServer) Start() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.isRunning {
		return fmt.Errorf("Redis代理已经在运行")
	}

	listener, err := net.Listen("tcp", s.config.LocalAddr)
	if err != nil {
		return fmt.Errorf("无法在 %s 上监听: %v", s.config.LocalAddr, err)
	}

	s.listener = listener
	s.isRunning = true
	log.Printf("Redis代理在 %s 上启动，转发到 %s", s.config.LocalAddr, s.config.RemoteAddr)

	// 启动代理处理协程
	s.wg.Add(1)
	go s.handleConnections()
	return nil
}

// Stop 停止Redis代理
func (s *RedisServer) Stop() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if !s.isRunning {
		return fmt.Errorf("Redis代理未运行")
	}

	err := s.listener.Close()
	s.isRunning = false
	log.Printf("Redis代理已停止")

	// 等待所有连接处理完毕
	s.wg.Wait()
	return err
}

// 处理传入连接
func (s *RedisServer) handleConnections() {
	defer s.wg.Done()

	for {
		clientConn, err := s.listener.Accept()
		if err != nil {
			// 如果监听器已关闭，直接退出
			if isNetClosedErr(err) {
				return
			}
			log.Printf("接受连接失败: %v", err)
			continue
		}

		// 为每个连接启动新的处理协程
		go s.handleClient(clientConn)
	}
}

// 处理客户端连接
func (s *RedisServer) handleClient(clientConn net.Conn) {
	defer clientConn.Close()

	// 连接到Redis服务器
	redisConn, err := net.Dial("tcp", s.config.RemoteAddr)
	if err != nil {
		log.Printf("连接Redis服务器失败: %v", err)
		return
	}
	defer redisConn.Close()

	// 双向数据拷贝
	var wg sync.WaitGroup
	wg.Add(2)

	// 客户端 -> Redis
	go func() {
		defer wg.Done()
		if _, err := io.Copy(redisConn, clientConn); err != nil && !isNetClosedErr(err) {
			log.Printf("从客户端复制数据失败: %v", err)
		}
		// 连接断开时关闭另一端
		redisConn.Close()
	}()

	// Redis -> 客户端
	go func() {
		defer wg.Done()
		if _, err := io.Copy(clientConn, redisConn); err != nil && !isNetClosedErr(err) {
			log.Printf("从Redis复制数据失败: %v", err)
		}
		// 连接断开时关闭另一端
		clientConn.Close()
	}()

	// 等待两个方向都完成
	wg.Wait()
}

// 判断是否是网络连接关闭错误
func isNetClosedErr(err error) bool {
	if err == nil {
		return false
	}
	return err == io.EOF || err == net.ErrClosed ||
		err.Error() == "use of closed network connection"
}
